---
title: 'watch'
section: 'API'
subSection: 'Utils'
description: 'watch for changes.'
---

# watch

#### subscription via a getter

This utility supports subscribing to multiple proxy objects (unlike `subscribe` which listens to only a single proxy). Proxy objects are subscribed with a `get` function passed to the callback.

Any changes to the proxy object (or its child proxies) will rerun the callback.

Also note the callback will run once immediately when `watch` is called, even if the proxies have not been yet mutated, to establish the initial subscriptions.

```js
import { proxy } from 'valtio'
import { watch } from 'valtio/utils'

const userState = proxy({ user: { name: 'Juuso' } })
const sessionState = proxy({ expired: false })

watch((get) => {
  // `get` adds `sessionState` to this callback's watched proxies
  get(sessionState)
  const expired = sessionState.expired
  // Or call it inline
  const name = get(userState).user.name
  console.log(`${name}'s session is ${expired ? 'expired' : 'valid'}`)
})
// 'Juuso's session is valid'
sessionState.expired = true
// 'Juuso's session is expired'
```

#### cleanup

You may return a cleanup function that runs both:

- Before each re-invocation of the callback (i.e. due to a watched proxy changing)
- When the `watch` itself is stopped (by calling the cleanup function returned by `watch`)

```js
watch((get) => {
  const expired = get(sessionState).expired
  const name = get(userState).user.name
  console.log(`${name}'s session is ${expired ? 'expired' : 'valid'}`)
  return () => {
    if (expired) {
      console.log('Cleaning up')
    }
  }
})
// Output from 1st immediate invocation of the callbcak
// 'Juuso's session is valid'

// Changing a dependency will invoke the cleanup callback first,
// but the captured `expired` is false, so we only see output from the
// 2nd invocation of the callback.
sessionState.expired = true
// 'Juuso's session is expired'

// Changing a dependency will again invoke the cleanup callback,
// and `expired` is true now, so we output from both our cleanup
// function as well as the 3rd invocation of the callback.
setTimeout(() => {
  userState.user.name = 'Anonymous'
}, 200)
// 200ms -> 'Anonymous's session is expired'
// 'Cleaning up' logged
```

#### gotchas

If you remove the setTimeout in the example above, 'Juuso's session is expired' will become 'Anonymous's session is expired', logged twice. Valtio will batch updates by default. You may pass `{sync: true}` as a second argument to `watch` to disable batching.

#### no usage tracking

`watch` currently does not implement the usage tracking of `useSnapshot`, so the callback will rerun anytime a watched proxy (or child proxy) has any fields mutated, regardless of the fields accessed within the `callback`'s code.

And the return value of `get` is just the proxy itself, not a snapshot.

This is because `watch` is a vanilla primitive built on top of `subscribe`. It is potentially possible for `watch`, or a new `watch`-like method, to implement usage tracking in the future, see [this discussion](https://github.com/pmndrs/valtio/discussions/640) if interested.
